home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 March / EnigmA AMIGA RUN 05 (1996)(G.R. Edizioni)(IT)[!][issue 1996-03][Skylink CD IV].iso / earcd / program / ixemlsrc.lha / ixemul / utils / ixtrace.c < prev    next >
C/C++ Source or Header  |  1996-01-24  |  11KB  |  468 lines

  1. /*
  2.  *  This file is part of ixemul.library for the Amiga.
  3.  *  Copyright (C) 1991, 1992  Markus M. Wild
  4.  *  Changed to avoid buffer overflows by J. Hoehle and
  5.  *  restricted output length for: str(n)cat, strlen
  6.  *
  7.  *  This library is free software; you can redistribute it and/or
  8.  *  modify it under the terms of the GNU Library General Public
  9.  *  License as published by the Free Software Foundation; either
  10.  *  version 2 of the License, or (at your option) any later version.
  11.  *
  12.  *  This library is distributed in the hope that it will be useful,
  13.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  *  Library General Public License for more details.
  16.  *
  17.  *  You should have received a copy of the GNU Library General Public
  18.  *  License along with this library; if not, write to the Free
  19.  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  */
  21.  
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <unistd.h>
  25. #include <string.h>
  26. #include <sys/tracecntl.h>
  27. #include <signal.h>
  28. #include <fcntl.h>
  29. #include <sys/ioctl.h>
  30. #include <sys/ioctl_compat.h>
  31. #include <sys/termios.h>
  32. #include <exec/types.h>
  33. #include <libraries/dos.h>
  34. #include <proto/exec.h>
  35. #include "ixtrace.h"
  36.  
  37. extern struct MsgPort *CreatePort (char *, int);
  38. extern void DeletePort (struct MsgPort *);
  39.  
  40. #define OUT_WIDTH  80    /* big enough (>30) to hold first information */
  41.  
  42. static void print_call (FILE *output, struct trace_packet *tp);
  43.  
  44. int print_all = 0;
  45. int skip_sigsetmask = 0;
  46. int skip_calls = 0;
  47. FILE *output;
  48. char VERSION[] = "$VER: ixtrace 1.3 (11-Dec-95)";
  49.  
  50. void
  51. dummy_handler ()
  52. {
  53. }
  54.  
  55. int
  56. main (int argc, char *argv[])
  57. {
  58.   char *logfile = "-";
  59.   struct trace_packet tp;
  60.   struct trace_packet *tpz;
  61.   int *tpz_;
  62.   struct MsgPort *mp;
  63.   int c, in = 0;
  64.  
  65.   memset ((char *) &tp, '\000', sizeof (tp));
  66.   signal (SIGMSG, dummy_handler);
  67.  
  68.   while ((c = getopt (argc, argv, "aimo:p:s:n:")) != EOF)
  69.     switch (c)
  70.       {
  71.       case 'a':
  72.     print_all = 1;
  73.     break;
  74.  
  75.       case 'i':
  76.     in = 1;
  77.     break;
  78.  
  79.       case 'm':
  80.     skip_sigsetmask = 1;
  81.     break;
  82.  
  83.       case 'o':
  84.     logfile = optarg;
  85.     break;
  86.  
  87.       case 'p':
  88.     tp.tp_pid = atoi (optarg);
  89.     break;
  90.     
  91.       case 'n':
  92.     skip_calls = atoi (optarg);
  93.     if (skip_calls < 0)
  94.     {
  95.       fprintf(stderr, "invalid argument for option -n\n");
  96.       exit(1);
  97.     }
  98.     break;
  99.     
  100.       case 's':
  101.     tp.tp_syscall = atoi (optarg);
  102.     break;
  103.  
  104.       default:
  105.     fprintf (stderr, "%s [-a] [-m] [-n N] [-o logfile] [-p pid] [-s syscall-number]\n", argv[0]);
  106.     fprintf (stderr, "  -a  trace all calls (else __-calls are skipped)\n");
  107.     fprintf (stderr, "  -i  trace entry to functions. Default is exit.\n");
  108.     fprintf (stderr, "  -m  skip sigsetmask() calls (they're heavily used inside the library)\n");
  109.     fprintf (stderr, "  -n  skip the first N traces\n");
  110.     fprintf (stderr, "  -o  log output to logfile (default is stdout)\n");
  111.     fprintf (stderr, "  -p  only trace process pid (default is to trace all processes)\n");
  112.     fprintf (stderr, "  -s  only trace this syscall (default is to trace all calls)\n");
  113.  
  114.         return 1;
  115.       }
  116.  
  117.   if (logfile[0] == '-' && !logfile[1])
  118.     output = stdout;
  119.   else
  120.     output = fopen (logfile, "w");
  121.  
  122.   if (!output)
  123.     {
  124.       perror ("fopen");
  125.       return 1;
  126.     }
  127.  
  128.   if ((mp = CreatePort (0, 0)))
  129.     {
  130.       tp.tp_tracer_port = mp;
  131.       if (tracecntl (TRACE_INSTALL_HANDLER, &tp) == 0)
  132.     {
  133.       while (1)
  134.         {
  135.           struct Message *msg;
  136.           long sigs;
  137.  
  138.           sigs = Wait ((1 << mp->mp_SigBit) | SIGBREAKF_CTRL_C);
  139.           while ((msg = GetMsg (mp)))
  140.         {
  141.               if (msg != (struct Message *) &tp)
  142.             {
  143.               fprintf (stderr, "Got alien message! Don't do that ever again ;-)\n");
  144.             } 
  145.               else
  146.             {
  147.               if (in)
  148.             tp.tp_action = TRACE_ACTION_JMP;
  149.               if (! tp.tp_is_entry || tp.tp_action == TRACE_ACTION_JMP)
  150.                 print_call (output, &tp);
  151.             }
  152.               Signal ((struct Task *) msg->mn_ReplyPort, SIGBREAKF_CTRL_E);
  153.             }
  154.           if (sigs & SIGBREAKF_CTRL_C)
  155.         break;
  156.         }
  157.       tracecntl (TRACE_REMOVE_HANDLER, &tp);
  158.     }
  159.       else
  160.     perror ("tracecntl");
  161.       
  162.       DeletePort (mp);
  163.     }
  164.   else
  165.     perror ("CreatePort");
  166. }
  167.  
  168.  
  169. /* should help make things less mystic... */
  170. #define TP_SCALL(tp) (tp->tp_argv[0])
  171. /* this is only valid if !tp->tp_is_entry */
  172. #define TP_RESULT(tp) (tp->tp_argv[1])
  173. #define TP_ERROR(tp) (* tp->tp_errno)
  174. /* tp_argv[2] is the return address */
  175. #define TP_FIRSTARG(tp) (tp->tp_argv[3])
  176.  
  177. void
  178. print_call (FILE *output, struct trace_packet *tp)
  179. {
  180.   char line[OUT_WIDTH+2];    /* for \n\0 */
  181.   char *argfield;
  182.   int space, len;
  183.   struct call *c;
  184.  
  185.   space = sizeof (line) - 1;
  186.   len = sprintf (line, "$%lx: %c", (unsigned long) tp->tp_message.mn_ReplyPort,
  187.                tp->tp_is_entry ? '>' : '<');
  188.   argfield = line + len;
  189.   space -= len;
  190.  
  191.   if (TP_SCALL (tp) > sizeof (call_table) / sizeof (struct call))
  192.     {
  193.       if (tp->tp_is_entry)
  194.         sprintf (argfield, "SYS_%d()\n", TP_SCALL (tp));
  195.       else
  196.         sprintf (argfield, "SYS_%d() = $%lx (%d)\n", 
  197.           TP_SCALL (tp), (unsigned long) TP_RESULT (tp), TP_ERROR (tp));
  198.     }
  199.   else
  200.     {
  201.       c = call_table + TP_SCALL (tp);
  202.  
  203.       if ((!print_all && !c->interesting) || 
  204.       (skip_sigsetmask && TP_SCALL (tp) == SYS_sigsetmask))
  205.     return;
  206.  
  207.       /* we can write space-1 real characters in the buffer, \n is not counted */
  208.       c->func (argfield, space-1, c, tp);
  209.     }
  210.  
  211.   if (skip_calls == 0)
  212.     fputs (line, output);
  213.   else
  214.     skip_calls--;
  215. }
  216.  
  217. /* the program contained a bug du to the fact that
  218.  * when snprintf or vsnprintf are called with a zero or negative size,
  219.  * they return -1 as an error marker but not any length.
  220.  */
  221.  
  222. static void
  223. vp (char *buf, int len, struct call *c, struct trace_packet *tp)
  224. {
  225.   int nl = snprintf (buf, len+1, "%s", c->name);
  226.  
  227.   len -= nl; if (len <= 0) goto finish;
  228.   buf += nl;
  229.   if (tp->tp_is_entry || !c->rfmt[0])
  230.     vsnprintf (buf, len+1, c->fmt, (_VA_LIST_) & TP_FIRSTARG (tp));
  231.   else
  232.     {
  233.       nl = vsnprintf (buf, len+1, c->fmt, (_VA_LIST_) & TP_FIRSTARG (tp));
  234.       len -= nl; if (len <= 0) goto finish;
  235.       buf += nl;
  236.       nl = snprintf (buf, len+1, "=");
  237.       len -= nl; if (len <= 0) goto finish;
  238.       buf += nl;
  239.       nl = vsnprintf (buf, len+1, c->rfmt, (_VA_LIST_) & TP_RESULT (tp));
  240.       len -= nl; if (len <= 0) goto finish;
  241.       buf += nl;
  242.       nl = snprintf (buf, len+1, " (%d)", TP_ERROR (tp));
  243.     }
  244.  
  245.   finish:
  246.   strcat (buf, "\n");
  247. }
  248.  
  249. const char *
  250. get_fcntl_cmd (int cmd)
  251. {
  252.   switch (cmd)
  253.     {
  254.     case F_DUPFD:
  255.     return "F_DUPFD";
  256.  
  257.     case F_GETFD:
  258.     return "F_GETFD";
  259.  
  260.     case F_SETFD:
  261.     return "F_SETFD";
  262.  
  263.     case F_GETFL:
  264.     return "F_GETFL";
  265.  
  266.     case F_SETFL:
  267.     return "F_SETFL";
  268.     
  269.     case F_GETOWN:
  270.     return "F_GETOWN";
  271.  
  272.     case F_SETOWN:
  273.     return "F_SETOWN";
  274.  
  275. #ifdef F_GETLK
  276.     case F_GETLK:
  277.     return "F_GETLK";
  278. #endif
  279.  
  280. #ifdef F_SETLK
  281.     case F_SETLK:
  282.     return "F_SETLK";
  283. #endif
  284.  
  285. #ifdef F_SETLKW
  286.     case F_SETLKW:
  287.     return "F_SETLKW";
  288. #endif
  289.  
  290.     default:
  291.     return "F_unknown";
  292.     }
  293. }
  294.  
  295. char *
  296. get_open_mode (int mode)
  297. {
  298.   static char buf[120];
  299.   
  300.   switch (mode & O_ACCMODE)
  301.     {
  302.     case O_RDONLY: 
  303.       strcpy (buf, "O_RDONLY");
  304.       break;
  305.       
  306.     case O_WRONLY:
  307.       strcpy (buf, "O_WRONLY");
  308.       break;
  309.       
  310.     case O_RDWR:
  311.       strcpy (buf, "O_RDWR");
  312.       break;
  313.       
  314.     default:
  315.       strcpy (buf, "O_illegal");
  316.       break;
  317.     }
  318.  
  319. #define ADD(flag) \
  320.   if (mode & flag) strcat (buf, "|" #flag);
  321.  
  322.   ADD (O_NONBLOCK);  
  323.   ADD (O_APPEND);
  324.   ADD (O_SHLOCK);
  325.   ADD (O_EXLOCK);
  326.   ADD (O_ASYNC);
  327.   ADD (O_FSYNC);
  328.   ADD (O_CREAT);
  329.   ADD (O_TRUNC);
  330.   ADD (O_EXCL);
  331. #undef ADD
  332.   
  333.   return buf;
  334. }
  335.  
  336. char *
  337. get_ioctl_cmd (int cmd)
  338. {
  339.   static char buf[12];
  340.  
  341.   /* only deal with those commands that are really implemented somehow in
  342.      ixemul.library. The others are dummies anyway, so they don't matter */
  343.  
  344.   switch (cmd)
  345.     {
  346.     case FIONREAD:
  347.       return "FIONREAD";
  348.  
  349.     case FIONBIO:
  350.       return "FIONBIO";
  351.  
  352.     case FIOASYNC:
  353.       /* not yet implemented, but important to know if some program tries
  354.          to use it ! */
  355.       return "FIOASYNC";
  356.  
  357.     case TIOCGETA:
  358.       return "TIOCGETA";
  359.  
  360.     case TIOCSETA:
  361.       return "TIOCSETA";
  362.  
  363.     case TIOCSETAW:
  364.       return "TIOCSETAW";
  365.  
  366.     case TIOCSETAF:
  367.       return "TIOCSETAF";
  368.  
  369.     case TIOCGETP:
  370.       return "TIOCGETP";
  371.  
  372.     case TIOCSETN:
  373.       return "TIOCSETN";
  374.  
  375.     case TIOCSETP:
  376.       return "TIOCSETP";
  377.  
  378.     case TIOCGWINSZ:
  379.       return "TIOCGWINSZ";
  380.  
  381.     case TIOCOUTQ:
  382.       return "TIOCOUTQ";
  383.  
  384.     case TIOCSWINSZ:
  385.       return "TIOCSWINSZ";
  386.       
  387.     default:
  388.       sprintf (buf, "$%lx", (unsigned long) cmd);
  389.       return buf;
  390.     }
  391. }
  392.  
  393.  
  394. static void
  395. vp_fcntl (char *buf, int len, struct call *c, struct trace_packet *tp)
  396. {
  397.   int *argv =  & TP_FIRSTARG (tp);
  398.   
  399.   if (tp->tp_is_entry)
  400.     if (argv[1] == F_GETFL || argv[1] == F_SETFL)
  401.       snprintf (buf, len+1, "fcntl(%d, %s, %s)",
  402.             argv[0], get_fcntl_cmd (argv[1]), get_open_mode (argv[2]));
  403.     else
  404.       snprintf (buf, len+1, "fcntl(%d, %s, %d)",
  405.             argv[0], get_fcntl_cmd (argv[1]), argv[2]);
  406.   else
  407.     if (argv[1] == F_GETFL || argv[1] == F_SETFL)
  408.       snprintf (buf, len+1, "fcntl(%d, %s, %s) = %d (%d)",
  409.             argv[0], get_fcntl_cmd (argv[1]), 
  410.         get_open_mode (argv[2]), TP_RESULT (tp), TP_ERROR (tp));
  411.     else
  412.       snprintf (buf, len+1, "fcntl(%d, %s, %d) = %d (%d)",
  413.             argv[0], get_fcntl_cmd (argv[1]), argv[2], 
  414.         TP_RESULT (tp), TP_ERROR (tp));
  415.  
  416.   strcat (buf, "\n");
  417. }
  418.  
  419.  
  420. static void
  421. vp_ioctl (char *buf, int len, struct call *c, struct trace_packet *tp)
  422. {
  423.   int *argv = & TP_FIRSTARG (tp);
  424.   
  425.   if (tp->tp_is_entry)
  426.     snprintf (buf, len+1, "ioctl(%d, %s, $%lx)",
  427.           argv[0], get_ioctl_cmd (argv[1]), argv[2]);
  428.   else
  429.     snprintf (buf, len+1, "ioctl(%d, %s, $%lx) = %d (%d)",
  430.           argv[0], get_ioctl_cmd (argv[1]), argv[2],
  431.           TP_RESULT (tp), TP_ERROR (tp));
  432.  
  433.   strcat (buf, "\n");
  434. }
  435.  
  436.  
  437. static void
  438. vp_open (char *buf, int len, struct call *c, struct trace_packet *tp)
  439. {
  440.   int *argv = & TP_FIRSTARG (tp);
  441.  
  442.   if (tp->tp_is_entry)
  443.     snprintf (buf, len+1, "open(\"%s\", %s)", argv[0], get_open_mode (argv[1]));
  444.   else
  445.     snprintf (buf, len+1, "open(\"%s\", %s) = %d (%d)", argv[0], 
  446.           get_open_mode (argv[1]), TP_RESULT (tp), TP_ERROR (tp));
  447.  
  448.   strcat (buf, "\n");
  449. }
  450.  
  451. static void
  452. vp_pipe (char *buf, int len, struct call *c, struct trace_packet *tp)
  453. {
  454.   int *argv = & TP_FIRSTARG (tp);
  455.  
  456.   if (tp->tp_is_entry)
  457.     snprintf (buf, len+1, "pipe($%lx)", argv[0]);
  458.   else
  459.     {
  460.       int *pv = (int *) argv[0];
  461.     
  462.       snprintf (buf, len+1, "pipe([%d, %d]) = %d (%d)", 
  463.         pv[0], pv[1], TP_RESULT (tp), TP_ERROR (tp));
  464.     }
  465.  
  466.   strcat (buf, "\n");
  467. }
  468.